#ifndef SPECIMEN_HPP
#define SPECIMEN_HPP
#include <cstddef>
#include "CrossPlatform.hpp"
#include <vector>
#include <cmath>
//#include <string>

///\brief Type for gene
typedef long double Gene;

///\brief Class modelling single specimen
class Specimen
{
  unsigned  _dimensions; ///< dimensionality of problem
  Gene _fitness; ///< fitness value of a specimen
  Gene *_genes; ///< array of genes
public:
  Specimen(); ///< Default constructor
  Specimen(const Specimen &argument);  ///< Copy constructor
  ~Specimen(); ///< Destructor
  ///< logical assignment operator
  Specimen &operator=(const Specimen &argument);
  ///< Method initializing object
  void init(int dimensions);
  /*!
   * \brief Method initializing object and assigning random gene values
   *
   * \param maxX - max possible values of generated coordinates
   * \param minX - max possible values of generated coordinates
   */
  void initRandom(int dimensions,
		  const std::vector<Gene> &maxX,
		  const std::vector<Gene> &minY);
  
  ///\brief will not be used
  void singlePointCrossover(const Specimen &parent,
			    Specimen &childA,Specimen &childB) const;
  ///\brief also will not be used
  void multiPointCrossover(const Specimen &parent,
			    Specimen &childA,Specimen &childB) const;

  /*!
   * \brief Method for creating offspring by algebraic random crossover
   *
   * Method creates new specimens as linear combination of parents A and B:
   * C=a*A+(1-a)*B, where "a" is a random number from betwen 0 and 1.
   * The second child is created using factor b=1-a.
   *
   * \param parent - second parent for crossover
   * \param childA - first child created using parameter of value a
   * \param childB -second child created using parameter of value 1-a
   */ 
  void algebraicRandCrossover(const Specimen &parent,
			      Specimen &childA,Specimen &childB) const;

  
  /*!
   * \brief Method for creating offspring by algebraic deterministic crossover
   *
   * Method creates new specimens as linear combination of parents A and B:
   * C=a*A+(1-a)*B, where "a" is a parameter of value from betwen 0 and 1.
   * The second child is created using factor b=1-a.
   *
   * \param parent - second parent for crossover
   * \param childA - first child created using parameter of value a
   * \param childB -second child created using parameter of value 1-a
   * \param proportion - value of a
   */
  void algebraicDetCrossover(const Specimen &parent,
			     Specimen &childA,Specimen &childB,
			     const double &proportion) const;


  /*!
   * \brief Method for creating offspring using uniform mutation
   *
   * Method creates offspring of specimen by picking random gene and assigning
   * it a random value
   *
   * \param maxX - max possible values of generated coordinates
   * \param minX - max possible values of generated coordinates
   */
  Specimen uniformMutation(const std::vector<Gene> &minX,
			   const std::vector<Gene> &maxX)const;
  /*!
   * \brief Index operator
   *
   * \param index - number of picked gene
   *
   * \pre index value must lay between 0 and number of problem dimensions
   *
   * \return Reference to picked gene
   */
   Gene &operator[](const size_t& index);
  /*!
   * \brief Index operator, const version
   *
   * \param index - number of picked gene
   *
   * \pre index value must lay between 0 and number of problem dimensions
   *
   * \return Const reference to picked gene
   */
  const Gene &operator[](const size_t& index)const;
  ///\brief Getter method for fitness value
  long double getFitness(){return _fitness;}
  ///\brief Setter method for fitness value
  void setFitness(const long double &fitness){_fitness=fitness;}
  ///\brief Gettermethod for number of dimensions of problem
  unsigned getDimensions(){return _dimensions;}
  /*!
   * \brief Greater-than operator
   *
   * \param arg - specimen which should have lesser value than the invoking one
   *
   * \retval True - invoking specimen has greater value than arg specimen
   * \retval False - invoking specimen has lesser or equal value to arg specimen
   */
  bool operator>(const Specimen &arg)const{return _fitness>arg._fitness;}
  /*!
   * \brief Lesser-than operator
   *
   * \param arg - specimen which should have greater value than the invoking one
   *
   * \retval True - invoking specimen has lesser value than arg specimen
   * \retval False - invoking specimen has greater or equal value to arg 
   * specimen
   */
  bool operator<(const Specimen &arg)const{return _fitness<arg._fitness;}

  /*!
   * \brief Method measuring distance between two specimens
   *
   * \param arg - specimen to which distance from this specimen will be measured
   *
   * \return distance betwen this and arg specimens
   */
  double measureDistance(const Specimen &arg)const;

};

#endif
